from django.shortcuts import render

# Create your views here.
from rest_framework.response import Response
from rest_framework.views import APIView

#  app.users 我们已经告知系统子子应用在哪里了,不需要添加apps了
# from apps.users.models import User
from celery_tasks.email.tasks import send_active_email
from goods.models import SKU
from goods.serializers import HostSKUSerializer
from users.models import User, Address
from users.utils import generic_active_url, get_active_user

"""
校验用户输入的用户名是否重复
一　确认需求
二　确定采用那种请求方式　和　url
三　实现

１．前端发送一个ajax请求，给后端，参数是用户名

２．后端接收用户名
３．检验用户名是否重复
４．返回响应

请求方式   GET
请求路径   /users/usernames/(?P<username>\w{4,20})/count/
请求参数　　username  用户输入的用户名，放入路径中
返回响应　　count  count = 0 此用户名不存在可以创建　　否则改用户名不能使用

"""


class RegisterUsernameCountView(APIView):
    """
    １．前端传递过来的数据已经在url中校验过了
    ２．我们不需要序列化器了
    """

    def get(self, request, username):
        # ２．后端接收用户名
        #  已经在路径中接收
        # ３．检验用户名是否重复
        #  count = 0 表示该用户名没有注册过
        #  count = 1 表示该用户已经注册过了
        count = User.objects.filter(username=username).count()
        # ４．返回响应
        return Response({'count': count})


"""
校验用户输入的手机号是否重复
1.前端发送一个ajax请求，给后端，参数是手机号
2.接收参数　手机号
3.校验手机手机号是否重复
4.返回响应

请求方式　GET
请求路径　/users/phones/(?p<mobile>1[345789]\d{9})/count
请求参数　mobile 用户输入的手机号
返回响应　count  count = 0 此手机号不存在，用户可以创建　　否则改用户不能创建
"""


class RegisterPhonesCountView(APIView):
    def get(self, request, mobile):
        # 2.接收参数　手机号
        # 在路径中已经接收了参数
        # 3.校验手机手机号是否重复
        count = User.objects.filter(mobile=mobile).count()
        # 4.返回响应
        return Response({'count': count})


"""
１．当用户点击注册的时候，前端需要发送一个请求，将用户的用户名，密码，确认密码，手机号，短信验证码，是否同意协议留个参数传递过来
２．获取前端传递的参数
３．校验参数
４．参数存入数据库
５．返回响应

请求方式　　POST
请求路径　　users/
请求参数　　username(用户名) password(第一次密码) password2(第二次密码) mobile(手机号) sms_code(短信验证码) allow(是否同意协议)
返回响应　　返回字典列表
"""

from users.serializers import RegisterCreateUser, UserCenterSerializer, UserEmailSerializer, AddressSerializer, \
    UpdateAddressSerializer, UserBrowsingHistorySerializer


#  可以使用　CreateAPIView
class RegisterCreateUserView(APIView):
    """用户注册"""

    def post(self, request):
        # ２．获取前端传递的参数
        data = request.data
        # ３．校验参数
        serializer = RegisterCreateUser(data=data)
        serializer.is_valid()
        # ４．参数存入数据库
        serializer.save()
        # ５．返回响应
        return Response(serializer.data)


"""
用户注册后，直接跳转到首页页面，这时默认表示已经登陆
应该返回一个token
"""

from rest_framework.permissions import IsAuthenticated

# class UserCenterView(APIView):
#     """
#     用户在访问个人中心的时候，我们应该将个人信息返回获取
#     如何获取一个登陆用户　前端需要发送一个token
#     获取用户信息
#     返回数据
#     """
#
#     #  设置权限　需要登陆用户才能访问
#     permission_classes = [IsAuthenticated]
#
#     def get(self, request):
#         # 获取用户信息
#         user = request.user
#         # 返回数据
#         serializer = UserCenterSerializer(user)
#         return Response(serializer.data)

from rest_framework.generics import RetrieveAPIView


class UserCenterView(RetrieveAPIView):
    """
    使用三级视图实现个人中心信息

    """
    #  设置权限　需要登陆用户才能访问
    permission_classes = [IsAuthenticated]

    queryset = User.objects.all()
    serializer_class = UserCenterSerializer

    def get_object(self):
        return self.request.user


"""
当用户输入邮箱，点击保存的时候，应该将邮箱的信息发送给后端

必须的登陆用户才能访问
获取前端发送过来的邮箱
校验参数
发送邮件
返回响应

请求方式　　PUT
请求路径　　users/emails/
请求参数　　用户写入的email
返回响应　　email

"""

#
# class UserEmailView(APIView):
#     #  必须登陆用户才能方式
#     permission_classes = [IsAuthenticated]
#
#     def put(self, request):
#         # 获取前端发送过来的邮箱
#         data = request.data
#         user = request.user
#         # 校验参数
#         serializer = UserEmailSerializer(instance=user, data=data)
#         serializer.is_valid(raise_exception=True)
#         #  更新数据
#         serializer.save()
#         # 发送邮件
#         # from django.core.mail import send_mail
#         # from django.conf import settings
#         # #  四个参数　
#         # # subject, 　标题
#         # subiect = '美多商城激活邮件'
#         # # message, 　内容
#         # message = ''
#         # # from_email, 　发件人
#         # from_email = settings.EMAIL_FROM
#         # # recipient_list,　收件人
#         # email = data.get('email')
#         # recipient_list = [email]
#         # verify_url = generic_active_url(user.id, email)
#         # html_message = '<p>尊敬的用户您好！</p>' \
#         #                '<p>感谢您使用美多商城。</p>' \
#         #                '<p>您的邮箱为：%s 。请点击此链接激活您的邮箱：</p>' \
#         #                '<p><a href="%s">%s<a></p>' % (email, verify_url, verify_url)
#         # send_mail(
#         #     subject=subiect,
#         #     message=message,
#         #     from_email=from_email,
#         #     recipient_list=recipient_list,
#         #     html_message=html_message
#         # )
#
#         #  使用异步发送邮件
#         send_active_email.delay(data.get('email'), user.id)
#         # 返回响应
#         return Response(serializer.data)


"""
使用三级视图实现邮件的更新
"""
from rest_framework.generics import UpdateAPIView


class UserEmailView(UpdateAPIView):
    #  登陆用户才能访问
    permission_classes = [IsAuthenticated]

    queryset = User.objects.all()

    serializer_class = UserEmailSerializer

    def get_object(self):
        return self.request.user


"""
当用户点击激活链接放到时候，会跳转到一个页面中　里面含有token　token含有id 和　email信息

接收token
解析token
获取用户对象
将用户标记为已经绑定邮箱
返回响应

请求方式　GET
请求路径　/users/emails/verification/?token=xxx
请求参数　token
返回响应　ok

"""
from rest_framework import status


class UserActiveEmail(APIView):
    def get(self, request):
        # 接收token
        token = request.query_params.get('token')
        if token is None:
            return Response(status=status.HTTP_400_BAD_REQUEST)
        # 解析token
        # 获取用户对象
        user = get_active_user(token)
        if user is None:
            return Response(status=status.HTTP_400_BAD_REQUEST)
        # 将用户标记为已经绑定邮箱
        user.email_active = True
        user.save()
        # 返回响应
        return Response({'mag': 'ok'})


"""
用户点击保存地址的时候　前端发送一个ajax请求，携带参数
接收参数
使用序列化器校验参数
数据保存到数据库
返回响应

请求方式　POST
请求路径　/users/addresses/
请求参数　title(地址名称) receiver(收货人) province(省) city(市) district(区县)
place(地址) mobile(手机) 可选参数　tel(固定电话) email(邮箱)
返回响应　字典数据
"""
from rest_framework.generics import CreateAPIView


class AddressView(CreateAPIView):
    #  必须认证用户才能访问
    permission_classes = [IsAuthenticated]
    serializer_class = AddressSerializer

    #  重写create方法　查询用户的绑定的地址数量，超而是个不能绑定
    def create(self, request, *args, **kwargs):
        count = request.user.addresses.count()
        if count > 20:
            return Response({'message': '保存地址数量已经达到上限'}, status=status.HTTP_400_BAD_REQUEST)
        # 调用父类的create方法
        return super().create(request, *args, **kwargs)


# class AddressView(APIView):
#     """
#     用户保存地址一级视图实现
#     """
#     def post(self, request):
#         #  获取参数
#         data = request.data
#         data['user'] = request.user.id
#         #  创建序列化器
#         serializer = AddressSerializer(data=data)
#         serializer.is_valid(raise_exception=True)
#         serializer.save()
#         #  返回响应　
#         return Response(serializer.data)


"""
当用户点击的收货地址管理的时候，前端发送一个和ajax请求，后端返回数据,列表展示
请求方式　GET
请求参数　无
请求路径　/users/getaddresses/
返回响应　用户id 是否默认地址　分页页数　地址的字典数据
"""
from rest_framework.generics import ListAPIView


class GetAddressView(ListAPIView):
    # 必须认证用户才能访问
    permission_classes = [IsAuthenticated]
    #  查询结果集是没有删除的数据
    queryset = Address.objects.filter(is_deleted=False)
    serializer_class = AddressSerializer

    #  重写list方法　返回指定响应数据
    def list(self, request, *args, **kwargs):
        #  获取结果集
        queryset = self.filter_queryset(self.get_queryset())
        #  经结果集放入序列化器
        serializer = self.get_serializer(queryset, many=True)
        #  返回响应
        return Response({
            'user_id': request.user.id,
            'default_address_id': request.user.default_address_id,
            'limit': 20,
            'addresses': serializer.data,
        })


"""
逻辑删除用户
请求方式　PUT
请求参数　用户id
请求路径　/users/addresses/（?P<pk>\d+）/
返回响应　ok
"""

from rest_framework.generics import DestroyAPIView


class DeleteAddressView(DestroyAPIView, UpdateAPIView):
    # 必须认证用户才能访问
    permission_classes = [IsAuthenticated]

    #  查询结果集必须是用户未删除的地址数据
    queryset = Address.objects.filter(is_deleted=False)
    serializer_class = AddressSerializer

    # 重写删除的方法　使用逻辑删除
    def destroy(self, request, *args, **kwargs):
        #  获取对象，这里是删除的对象
        instance = self.get_object()
        #  逻辑删除
        instance.is_deleted = True
        #  保存到数据库
        instance.save()
        return Response(status=status.HTTP_204_NO_CONTENT)


"""
修改用户title
请求方式　put
请求参数　用户id 用户输入的修改的内容
请求路径　/users/addresses/（?P<pk>\d+）/title
返回响应　ｏｋ
"""

from rest_framework.generics import UpdateAPIView


class UpdateAddressView(UpdateAPIView):
    # 必须认证用户才能访问
    permission_classes = [IsAuthenticated]

    #  查询结果集必须是用户未删除的地址数据
    queryset = Address.objects.filter(is_deleted=False)
    serializer_class = UpdateAddressSerializer


"""
设置用户的默认地址
请求方式　PUT
请求路径　/users/addresses/(?P<pk>\d+)/status/
请求参数　用户id
返回响应　ok
"""


class DefaultAddressView(UpdateAPIView):
    # 必须认证用户才能访问
    permission_classes = [IsAuthenticated]

    #  查询结果集必须是用户未删除的地址数据
    queryset = Address.objects.filter(is_deleted=False)
    serializer_class = AddressSerializer

    #  重写用户的update方法
    def update(self, request, *args, **kwargs):
        #  当前用户的默认地址等于当前用户设置的地址的id
        request.user.default_address = self.get_object()
        #  保存到数据库
        request.user.save()
        #  返回响应
        return Response({'message': 'ok'}, status=status.HTTP_200_OK)


"""
设置用户浏览历史记录，当用户浏览商品详情的时候，记录该用户浏览的商品的id(sku_id)，在用户浏览个人中心的时候展示给用户的浏览记录
浏览信息保存位置：
    可以保存到数据库，只需要保存用户的id和用户浏览的商品的id
    可以保存redis中，将用户的id和浏览商品的id保存到redis中，数据格式采用list,达到一个键对应多个数据


当用户浏览商品的详情信息的时候，前端发送一个post请求，携带参数商品的id(sku_id)
    必须是登陆用户才能访问
    获取当前用户
    后端接收参数开启序列化器校验参数
    链接redis
    获取商品的id
    先删除当前用户的对应的sku_id，达到去重效果
    保存数据到redis中
    限制保存数据的条数，这里是五条
    返回响应


请求方式　post
请求路径　/user/browerhistories/
请求参数　商品的id(sku_id)
返回响应　当前保存的商品id


当用户访问个人中心的时候，前端发送一个请求，获取用户的浏览商品记录
    必须是登陆用户才能访问
    获取当前用户
    链接redis
    根据当前用户的id从redis中获取对应的浏览数据，sku_ids
    遍历sku_ids，获取商品对象
    创建序列化器获取字典数据
    返回响应

请求方式　get
请求路径　/user/browerhistories/
请求参数　无
返回响应　商品的字典数据


"""
from django_redis import get_redis_connection


# class UserBrowsingHistoryView(APIView):
#     # 必须是登陆用户才能访问
#     permission_classes = [IsAuthenticated]
#
#     def post(self, request):
#         # 获取当前用户
#         user = request.user
#         # 后端接收参数开启序列化器校验参数
#         serializer = UserBrowsingHistorySerializer(data=request.data)
#         serializer.is_valid(raise_exception=True)
#         # 链接redis
#         redis_conn = get_redis_connection('history')
#         # 获取商品的id
#         sku_id = request.data.get('sku_id')
#         # 先删除当前用户的对应的sku_id，达到去重效果
#         redis_conn.lrem('history_%s' % user.id, 0, sku_id)
#         # 保存数据到redis中
#         redis_conn.lpush('history_%s' % user.id, sku_id)
#         # 限制保存数据的条数，这里是五条
#         redis_conn.ltrim('history_%s' % user.id, 0, 4)
#         # 返回响应
#         return Response(serializer.data)
#
#     def get(self, request):
#         # 获取当前用户
#         user = request.user
#         # 链接redis
#         redis_conn = get_redis_connection('history')
#         # 根据当前用户的id从redis中获取对应的浏览数据，sku_ids
#         #  由于只存储了五条用户的浏览信息数据，所有获取大于存储量的数据
#         sku_ids = redis_conn.lrange('history_%s' % user.id, 0, 5)
#         # 遍历sku_ids，获取商品对象
#         # skus = SKU.objects.filter(pk__in=sku_ids)  in  会打乱浏览的顺序
#         #  存储查询的对象
#         skus = []
#         for sku_id in sku_ids:
#             sku = SKU.objects.get(pk=sku_id)
#             skus.append(sku)
#         # 创建序列化器获取字典数据
#         serializer = HostSKUSerializer(skus, many=True)
#         # 返回响应
#         return Response(serializer.data)

class UserBrowsingHistoryView(CreateAPIView):
    """
    三级视图实现用户的商品历史浏览记录
    """
    #  登陆用户才能访问
    permission_classes = [IsAuthenticated]
    #  定义序列化器
    serializer_class = UserBrowsingHistorySerializer

    def get(self, request):
        # 获取当前用户
        user = request.user
        # 链接redis
        redis_conn = get_redis_connection('history')
        # 根据当前用户的id从redis中获取对应的浏览数据，sku_ids
        #  由于只存储了五条用户的浏览信息数据，所有获取大于存储量的数据
        sku_ids = redis_conn.lrange('history_%s' % user.id, 0, 5)
        # 遍历sku_ids，获取商品对象
        # skus = SKU.objects.filter(pk__in=sku_ids)  in  会打乱浏览的顺序
        #  存储查询的对象
        skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(pk=sku_id)
            skus.append(sku)
        # 创建序列化器获取字典数据
        serializer = HostSKUSerializer(skus, many=True)
        # 返回响应
        return Response(serializer.data)


from rest_framework_jwt.views import ObtainJSONWebToken
from utils.cart import merge_cookie_to_redis


class UserAuthorizationView(ObtainJSONWebToken):
    def post(self, request):
        # 调用jwt扩展的方法，对用户登录的数据进行验证
        response = super().post(request)

        # 如果用户登录成功，进行购物车数据合并
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            # 表示用户登录成功
            user = serializer.validated_data.get("user")
            # 合并购物车
            # merge_cart_cookie_to_redis(request, user, response)
            response = merge_cookie_to_redis(request, user, response)

        return response
